package liuch;

import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 〈一句话功能简述〉CountDownLatch、CyclicBarrier、Semaphore的使用<br> 〈功能详细描述〉
 *
 * @author 17101651 on 2018/3/5.
 * @see [相关类/方法]（可选）
 * @since [产品/模块版本] （可选）
 */
public class Thread_CountDownLatch_CyclicBarrier_Semaphore_Test {

    /**
     * 使用线程池
     */
    static void ThreadPoolExecutor() {
        int count = 100000;
        long timeStart_a = System.currentTimeMillis();
        final List<Integer> list = new LinkedList<Integer>();
        ThreadPoolExecutor tp = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(count));
        final Random random = new Random();
        for (int i = 0; i < count; i++) {
            tp.execute(new Runnable() {
                @Override
                public void run() {
                    list.add(random.nextInt());
                }
            });
        }
        tp.shutdown();
        try {
            boolean b = tp.awaitTermination(1, TimeUnit.DAYS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(System.currentTimeMillis() - timeStart_a);// 76
        System.out.println(list.size());// 100000
    }

    /**
     * 原生线程执行
     */
    static void Thread() {
        int count = 1000;
        long timeStart_a = System.currentTimeMillis();
        final List<Integer> list = new LinkedList<Integer>();
        final Random random = new Random();
        for (int i = 0; i < count; i++) {
            Thread thread = new Thread() {
                @Override
                public void run() {
                    list.add(random.nextInt());
                }
            };
            thread.start();
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName());
        System.out.println(System.currentTimeMillis() - timeStart_a);// 9966
        System.out.println(list.size());// 100000
    }

    /**
     * CountDownLatch CountDownLatch类位于java.util.concurrent包下，利用它可以实现类似计数器的功能。 比如有一个任务A，它要等待其他4个任务执行完毕之后才能执行，
     * 此时就可以利用CountDownLatch来实现这种功能了
     */
    static void CountDownLatch() {
        final CountDownLatch latch = new CountDownLatch(2);
        new Thread() {
            @Override
            public void run() {
                try {
                    System.out.println("子线程" + Thread.currentThread().getName() + "正在执行");
                    Thread.sleep(1000);
                    System.out.println("子线程" + Thread.currentThread().getName() + "执行完毕");
                    latch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
        new Thread() {
            @Override
            public void run() {
                try {
                    System.out.println("子线程" + Thread.currentThread().getName() + "正在执行");
                    Thread.sleep(1000);
                    System.out.println("子线程" + Thread.currentThread().getName() + "执行完毕");
                    latch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
        try {
            System.out.println("等待2个线程执行完毕");
            latch.await();
            System.out.println("2个子线程已经执行完毕");
            System.out.println("继续执行主线程");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * CyclicBarrier 功能描述:字面意思回环栅栏，通过它可以实现让一组线程等待至某个状态之后再全部同时执行。 叫做回环是因为当所有等待线程都被释放以后，CyclicBarrier可以被重用。
     * 我们暂且把这个状态就叫做barrier，当调用await()方法之后，线程就处于barrier了。 <br>
     * <p>
     * 参数parties指让多少个线程或者任务等待至barrier状态； 参数barrierAction为当这些线程都达到barrier状态时会执行的内容。
     * <p>
     * 〈功能详细描述〉 假若有若干个线程都要进行写数据操作，并且只有所有线程都完成写数据操作之后， 这些线程才能继续做后面的事情，此时就可以利用CyclicBarrier了
     *
     * @author 17101651
     */
    static void CyclicBarrier() {
        final CyclicBarrier cyclicBarrier = new CyclicBarrier(4);
        for (int i = 0; i < 4; i++) {
            new WorkerCyclicBarrier(cyclicBarrier).start();
        }
    }

    /**
     * 同上
     */
    static void CyclicBarrierWithRunable(Runnable runnable) {
        final CyclicBarrier cyclicBarrier = new CyclicBarrier(4, runnable);
        for (int i = 0; i < 4; i++) {
            new WorkerCyclicBarrier(cyclicBarrier).start();
        }
    }

    /**
     * CyclicBarrier 把cyclicBarrier指定await()一定时间
     */
    static void CyclicBarrierAwait() {
        final CyclicBarrier cyclicBarrier = new CyclicBarrier(4);
        for (int i = 0; i < 4; i++) {
            if (i == 3) {
                try {
                    Thread.sleep(5000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                new WorkerCyclicBarrierAwait(cyclicBarrier).start();
            } else {
                new WorkerCyclicBarrierAwait(cyclicBarrier).start();
            }
        }
    }

    /**
     * Semaphore :
     * <p>
     * Semaphore翻译成字面意思为 信号量，Semaphore可以控同时访问的线程个数， 通过 acquire() 获取一个许可，如果没有就等待，而 release() 释放一个许可。
     * <p>
     * 参数permits表示许可数目，即同时可以允许多少线程进行访问 public Semaphore(int permits) { sync = new NonfairSync(permits); }
     * 这个多了一个参数fair表示是否是公平的，即等待时间越久的越先获取许可 public Semaphore(int permits, boolean fair) { sync = (fair)? new
     * FairSync(permits) : new NonfairSync(permits); } 下面说一下Semaphore类中比较重要的几个方法，首先是acquire()、release()方法：
     * <p>
     * public void acquire() throws InterruptedException {  }     //获取一个许可 public void acquire(int permits) throws
     * InterruptedException { }    //获取permits个许可 public void release() { }          //释放一个许可 public void release(int
     * permits) { }    //释放permits个许可
     */
    static void Semaphore() {
        Semaphore semaphore = new Semaphore(5);
        for (int i = 0; i < 8; i++) {
            new WorkerSemphore(i, semaphore).start();
        }
    }

    /**
     * CyclicBarrier线程类
     */
    static class WorkerCyclicBarrier extends Thread {
        private CyclicBarrier cyclicBarrier;

        WorkerCyclicBarrier(CyclicBarrier cyclicBarrier) {
            this.cyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            System.out.println("线程" + Thread.currentThread().getName() + "正在写入数据...");
            try {
                Thread.sleep(3000);
                System.out.println("线程" + Thread.currentThread().getName() + "写入数据完毕,等待其他线程写入完毕");
                cyclicBarrier.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("所以线程写入完毕,继续处理其他任务...");
        }
    }

    /**
     * CyclicBarrier线程类
     */
    static class WorkerCyclicBarrierAwait extends Thread {
        private CyclicBarrier cyclicBarrier;

        WorkerCyclicBarrierAwait(CyclicBarrier cyclicBarrier) {
            this.cyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(3000);
                System.out.println("线程" + Thread.currentThread().getName() + "写入数据完毕,等待其他线程写入完毕");
                cyclicBarrier.await(2000, TimeUnit.MILLISECONDS);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "所有线程写入完毕，继续处理其他任务...");
        }
    }

    /**
     * Semphore线程类
     */
    static class WorkerSemphore extends Thread {
        private int count;
        private Semaphore semaphore;

        WorkerSemphore(int i, Semaphore semaphore) {
            this.count = i;
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            try {
                semaphore.acquire();
                System.out.println("工人" + this.count + "占用一个机器在生产....");
                Thread.sleep(3000);
                semaphore.release();
                System.out.println("工人" + this.count + "释放出机器");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * runnable
     */
    static class TestRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("当前线程" + Thread.currentThread().getName());
        }
    }

    /**
     * 多线程操作一个数据的问题
     */
    static class Ticket implements Runnable {

        private Lock ticketLock = new ReentrantLock();
        private int num = 100;
        private Object object = new Object();

        @Override
        public void run() {
            while (true) {
                ticketLock.lock();
                synchronized (object) {
                    if (num > 0) {
                        try {
                            Thread.sleep(10);
                            System.out.println(Thread.currentThread().getName() + "...sale..." + num--);
                        } catch (Exception e) {
                            e.printStackTrace();
                        } finally {
                            ticketLock.unlock();
                        }
                    } else {
                        break;
                    }
                }
            }
        }
    }

    /**
     * 测试join线程
     */
    static class DomioJoin implements Runnable {
        private Thread thread;

        DomioJoin(Thread thread) {
            this.thread = thread;
        }

        @Override
        public void run() {
            try {
                thread.join(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "线程结束");
        }
    }

    public static void main(String[] args) {
        /*Ticket ticket = new Ticket();
        Thread thread1 = new Thread(ticket);
        Thread thread2 = new Thread(ticket);
        Thread thread3 = new Thread(ticket);
        Thread thread4 = new Thread(ticket);
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();*/
        /*Thread previous = Thread.currentThread();
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(new DomioJoin(previous), i + "");
            thread.start();
            previous = thread;
        }
        try {
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + "线程结束");
        } catch (Exception e) {
            e.printStackTrace();
        }*/
        // 1.CountDownLatch测试等待所有线程都执行完毕后再开始执行主线程后面的任务
//        CountDownLatch();
        // 2.CyclicBarrier测试4个线程同时达到某一状态后开始执行子线程后面的任务
//        CyclicBarrier();
        // 3.CyclicBarrierAwait测试await一定时间，如果操作这个时间，其他线程还未执行完，则报错
//        CyclicBarrierAwait();
        // 4.CyclicBarrierWithRunable测试在所有线程达到一个点时，先执行runable下的方法
//        CyclicBarrierWithRunable(new Runnable() {
//            @Override
//            public void run() {
//                System.out.println("++++++++++++++++");
//            }
//        });
    }
}
